home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
276-300
/
279
/
mouseclock
/
mouseclock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-14
|
27KB
|
1,182 lines
/* MouseClock.c *************************************************************
*
* MouseClock ---- Ein Uhren-Utility, das ausnahmsweise nicht
* irgendwo auf einem obskuren Bildschirm
* (meinetwegen auch Workbench-Bildschirm)
* existiert, sondern sich in der Nähe des
* Mauszeigers aufhält. Die Position und
* der Bildschirm, auf dem sich die Anzeige
* von MouseClock aufhält, ist unabhängig vom
* Workbench-Bildschirm. Ähnlich wie beim
* Mauszeiger liegen die Sprites, die Mouseclock
* zur Anzeige verwendet, immer auf dem vordersten
* Bildschirm.
*
* Besonders stolz (soviel Eitelkeit darf ich
* mir hoffentlich gönnen) bin ich auf den Interrupt-
* code, der die Anzeige bewegt. Es hat auf
* Anhieb geklappt und ist noch nicht ein einziges
* mal abgeschmiert.
*
* Autor --------- Olaf Barthel, ED Electronic Design Hannover
* Brabeckstraße 35
* D-3000 Hannover 71
*
* Bundesrepublik Deutschland
*
* (C) Copyright 1989 by Olaf Barthel &
* ED Electronic Design Hannover
*
****************************************************************************/
#include <intuition/intuitionbase.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include <exec/interrupts.h>
#include <graphics/sprite.h>
#include <devices/timer.h>
#include <exec/memory.h>
/* Vorwärtsdeklarationen, um Compiler-Warnungen zu
* zu vermeiden.
*/
extern struct Library *OpenLibrary();
extern struct Window *OpenWindow();
extern struct ViewPort *ViewPortAddress();
extern struct Message *GetMsg();
extern struct MsgPort *CreatePort();
extern struct MsgPort *FindPort();
extern void *AllocMem();
extern PLANEPTR AllocRaster();
extern long AvailMem();
/* Globale Variablen, die zur Handhabung des Displays
* und des Fensters dienen.
*/
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Window *Window;
struct IntuiMessage *Massage;
struct MsgPort *MouseClockPort;
/* Wir orientieren uns zwar nicht am vordersten ViewPort,
* wenn wir die Sprites setzen, passen aber die Farben
* der Sprites an, wenn ein Bildschirm weniger als 32
* Farben hat.
*/
struct ViewPort *VPort;
/* Die beiden Sprites der Anzeige. */
struct SimpleSprite Position1,Position2;
/* Mit diesen Variablen wird später Schrift in die Sprites
* gedruckt.
*/
struct BitMap PointerBMap;
struct RastPort PointerRPort;
/* Aktuelle Position des Mauszeigers, soll die Interruptroutine
* den Mauszeiger bearbeiten?
*/
WORD CurX,CurY,DoPosition = FALSE;
/* Datenspeicher für die Spritedaten. */
UWORD Pointer1Data[(2 + 72) * 2],Pointer2Data[(2 + 72) * 2];
/* Zeichenfarben für Schrift und Hintergrund. */
UBYTE Render[3],Shadow[3];
/* Mit den folgenden Daten werden Fonts zum Zeichnen der
* Kurzinfo definiert.
*/
struct TextAttr AboutFont[3] =
{
{(UBYTE *)"topaz.font",8,FS_NORMAL ,FPF_ROMFONT},
{(UBYTE *)"topaz.font",8,FSF_BOLD ,FPF_ROMFONT},
{(UBYTE *)"topaz.font",8,FSF_ITALIC,FPF_ROMFONT}
};
/* Dies ist die "Kurzinfo", die gezeigt wird, wenn unser
* Fenster aktiviert worden ist. Der Titlebar des
* Workbench-Bildschirms wird ein wenig verschönert.
*/
struct IntuiText AboutTxt[4] =
{
{3,1,JAM1, 0,1,(struct TextAttr *)&AboutFont[1],(UBYTE *)"MouseClock", (struct IntuiText *)&AboutTxt[ 1]},
{2,1,JAM1, 88,1,(struct TextAttr *)&AboutFont[2],(UBYTE *)"v1.2", (struct IntuiText *)&AboutTxt[ 2]},
{2,1,JAM1,128,1,(struct TextAttr *)&AboutFont[0],(UBYTE *)"© 1989 by", (struct IntuiText *)&AboutTxt[ 3]},
{0,1,JAM1,232,1,(struct TextAttr *)&AboutFont[2],(UBYTE *)"Electronic Design Hannover", (struct IntuiText *)NULL}
};
/* Bitmapdaten um das ED-Symbol über dem Schließgadget
* zeichnen zu können.
*/
USHORT ClipMap[40] =
{
0xFFFF,0xF000,0xFFFF,0xF000,0xF001,0xF000,0xF7FF,0xF000,
0xFFFF,0xD000,0xF03F,0xD000,0xF7FF,0x9000,0xFFFF,0x3000,
0xF000,0x7000,0xFFFF,0xF000,
0x0000,0x0000,0x1FFF,0x0000,0x3FFF,0x8000,0x3800,0xC000,
0x1F80,0xE000,0x3FC0,0xE000,0x3801,0xE000,0x1FFF,0xC000,
0x0FFF,0x8000,0x0000,0x0000
};
/* Zum Einzeichnen des ED-Symbols notwendige Definition. */
struct Image ClipImage =
{
0,0,
20,10,2,
(USHORT *)ClipMap,
0x03,0x00,
(struct Image *)NULL
};
/* Dieses Fenster wird geöffnet, um u.A. festellen zu
* können, ob der Anwender das Programm beenden möchte,
* oder sich die Farbe des Mauszeigers geändert hat.
*/
struct NewWindow NewWindow =
{
561,0,
26,10,
1,1,
CLOSEWINDOW | NEWPREFS | REFRESHWINDOW | ACTIVEWINDOW,
RMBTRAP | WINDOWCLOSE | SIMPLE_REFRESH,
(struct Gadget *)NULL,
(struct Image *)NULL,
(STRPTR)NULL,
(struct Screen *)NULL,
(struct BitMap *)NULL,
0,0,
0,0,
WBENCHSCREEN
};
/* Falls sich DMouse irgendwo im Speicher versteckt, borgen
* wir den DMouse Mousetimeout, um die Sprites rechtzeitig
* verschwinden zu lassen.
*/
struct DMSFragment
{
struct MsgPort Port; /* Globaler Messageport. */
short Version;/* Aktuelle Version. */
short Acc; /* Beschleunigung. */
short AThresh;/* Beschleunigungsschwelle. */
long STo; /* Screentimeout. */
long MTo; /* Mousetimeout. */
};
/* Diese Variablen sind notwendig, wenn man sich vom
* CLI abkoppeln möchte, von dem man gestartet wird.
*/
long _stack = 4000;
long _priority = 1;
long _BackGroundIO = NULL;
char *_procname = "MouseClock v1.2";
/* Hilfsstrukturen zur Kontrolle des timer.device. */
struct timerequest *tr_TimerRequest= NULL;
struct MsgPort *tr_TimerPort = NULL;
/* Mit dieser Struktur wird die Routine zum Positionieren
* der Anzeige in den Vertical Blanking Interrupt gehängt.
*/
struct Interrupt VBlankServer;
/* Da wir diese Symbole noch brauchen, um in einigen
* Assemblerroutinen herumzukleistern, aber die Assembler-
* routinen, die gleich folgen werden, diese Symbole für
* den Compiler nicht sichtbar erzeugen, schustern wir
* ein wenig herum.
*/
extern void NuCloseScreen();
extern void HandleVBlank();
/* Hier wird später einmal ein Zeiger auf eine System-
* routine erscheinen, OpenScreen() um genau zu sein.
* Dieser Wert wird von SetFunction() zurückgeliefert,
* wenn wir in den Libraries herumstochern.
*/
long OldCloseScreen;
#asm
_HandleVBlank: MOVEM.L A2-A6/D2-D7,-(A7) ; Ein paar Register retten
JSR _geta4# ; Adressregister geraderücken
JSR _MyHandleVBlank ; C-Routine anspringen
CLR.L D0 ; Da wir im Interrupt sind,
; muß D0 gelöscht werden.
MOVEM.L (A7)+,A2-A6/D2-D7 ; Die Register restaurieren
RTS ; ...und weiter.
_NuCloseScreen: MOVEM.L D2/D3/A4/A6,-(SP) ; Ein paar Register retten
MOVE.L A0,-(SP) ; Screen-Zeiger als Argument
; übernehmen
JSR _geta4# ; Adressregister geraderücken
JSR _ModifiedCloseScreen ; C-Routine anspringen
ADDQ.L #4,SP ; Stack korrigieren
MOVE.L D0,A0 ; Screen weiterleiten
MOVE.L _OldCloseScreen,A1 ; Alte Routine merken
MOVEM.L (SP)+,D2/D3/A4/A6 ; Register restaurieren
JMP (A1) ; Alte Routine anspringen
#endasm
/* ModifiedCloseScreen(Screen) :
*
* Ein Patch für die CloseScreen() Routine, damit
* sich die Interrupt-Routine nicht an Bildschirme
* heranmacht, die gerade geschlossen werden.
*/
struct Screen *
ModifiedCloseScreen(Screen)
struct Screen *Screen;
{
/* Bildschirm nach hinten legen. */
ScreenToBack(Screen);
/* Zweimal auf den Durchlauf des Vertical Blanking
* warten, damit der Handler auch wirklich mitkriegt,
* daß er einen Bildschirm nicht manipulieren kann,
* den es in Zehntelsekunden nicht mehr geben wird.
* Gut, das ist die kompliziertere Methode, aber
* wenigstens geht sie nicht immer in die Hose,
* was ohne diesen Patch sehr häufig passiert.
*/
WaitTOF();
WaitTOF();
/* Man kann ja nicht immer alles auf dem Stack
* herumliegen lassen, also liefern wir den Zeiger
* zurück, damit die alte CloseScreen() Routine
* nicht im Regen steht.
*/
return(Screen);
}
/* MyHandleVBlank() :
*
* Dies ist eine echte Interrupt-Routine in C,
* ja das gibt es wirklich und es funktioniert
* sogar. In dieser Routine werden die Sprites
* bewegt und die Farben gesetzt. Auf diese
* Weise ist es wesentlich schneller als eine
* multitaskingfähige Unterroutine, die z.B.
* auf das timer.device wartet.
*/
void
MyHandleVBlank()
{
/* WER konnte es ahnen, daß Intuition diese
* Daten auf einen Bildschirm bezieht, der
* 640 Pixel in X-Richtung und 512 in Y-Richtung
* besitzt? Es hat mich eine Menge Zeit gekostet,
* herauszufinden, weshalb sich die Anzeige
* schneller bewegte als der Mauszeiger selbst,
* bis ich herausbekam, daß diese Daten
* nicht für Sprites gedacht sind, die sich nur
* in Lo-res Schritten bewegen können.
*/
CurX = IntuitionBase -> MouseX >> 1;
CurY = IntuitionBase -> MouseY >> 1;
/* Falls nötig, werden die Farben der Sprites
* an den aktuellen Bildschirm angepaßt.
*/
VPort = &IntuitionBase -> FirstScreen -> ViewPort;
/* Na woher wissen wir denn, wie tief der Bildschirm
* ist? Na, wozu hängt eine RasInfo am ViewPort?
*/
if(VPort -> RasInfo -> BitMap -> Depth < 5)
{
SetRGB4(VPort,22,Shadow[0],Shadow[1],Shadow[2]);
SetRGB4(VPort,21,Render[0],Render[1],Render[2]);
}
if(DoPosition)
{
/* Sprites an die Position rechts neben dem
* Mauszeiger rücken.
*/
MoveSprite(NULL,&Position1,CurX + 8,CurY);
MoveSprite(NULL,&Position2,CurX + 24,CurY);
}
}
/* AddVBlankServer() :
*
* Dies initialisiert eine Struktur, mit deren Hilfe
* ein Interruptserver in den Vertical Blanking
* Interrupt eingeklinkt wird.
*/
void
AddVBlankServer()
{
VBlankServer . is_Data = (APTR)NULL;
VBlankServer . is_Code = HandleVBlank;
VBlankServer . is_Node . ln_Succ= NULL;
VBlankServer . is_Node . ln_Pred= NULL;
VBlankServer . is_Node . ln_Type= NT_INTERRUPT;
VBlankServer . is_Node . ln_Pri = 0;
VBlankServer . is_Node . ln_Name= "MouseClock";
/* Herzlichen Dank an Dan Silva, er benutzt eine
* ähnliche Methode, um DPaint Colourcycling
* beizubringen. Ich hab's einfach einmal
* ausprobiert und es lief sofort!
*/
AddIntServer(5,&VBlankServer);
}
/* RemVBlankServer() :
*
* Wirft den Interruptserver wieder aus der Liste
* der Interrupts.
*/
void
RemVBlankServer()
{
/* Hoffentlich baut Exec keinen Mist und
* schickt den Server wirklich in die Wüste.
*/
RemIntServer(5,&VBlankServer);
}
/* OpenTimerDevice() :
*
* Öffnet das timer.device für unsere Zwecke.
*/
BOOL
OpenTimerDevice()
{
if(!(tr_TimerPort = (struct MsgPort *)CreatePort(NULL,0)))
return(FALSE);
if(!(tr_TimerRequest = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC | MEMF_CLEAR)))
{
DeletePort(tr_TimerPort);
return(FALSE);
}
/* Präzisionszeitgeber aktivieren. */
if(OpenDevice(TIMERNAME,UNIT_VBLANK,tr_TimerRequest,0))
{
FreeMem(tr_TimerRequest,(long)sizeof(struct timerequest));
DeletePort(tr_TimerPort);
return(FALSE);
}
tr_TimerRequest -> tr_node . io_Message . mn_ReplyPort = tr_TimerPort;
tr_TimerRequest -> tr_node . io_Command = TR_ADDREQUEST;
tr_TimerRequest -> tr_node . io_Flags = 0;
tr_TimerRequest -> tr_node . io_Error = 0;
return(TRUE);
}
/* CloseTimerDevice() :
*
* Gibt den angeforderten Speicher frei und schließt das
* timer.device.
*/
void
CloseTimerDevice()
{
if(tr_TimerRequest)
{
CloseDevice(tr_TimerRequest);
FreeMem(tr_TimerRequest,sizeof(struct timerequest));
}
if(tr_TimerPort)
DeletePort(tr_TimerPort);
}
/* WaitTime(Seconds,Micros) :
*
* Wartet eine Zeitperiode.
*/
void
WaitTime(Seconds,Micros)
register ULONG Seconds,Micros;
{
tr_TimerRequest -> tr_time . tv_secs = Seconds;
tr_TimerRequest -> tr_time . tv_micro = Micros;
DoIO(tr_TimerRequest);
}
/* OpenPixel6Font() :
*
* Aktiviert einen speziellen, 4 Pixel breiten und
* 6 Zeilen hohen Zeichensatz, mit dem später in die
* Sprites gezeichnet wird.
*/
struct TextFont *
OpenPixel6Font()
{
static struct TextFont Pixel6Font;
static long Pixel6Dump[138] =
{
0x04AA2240,0x00002E2E,0xEAEEEEE0,0x0204E4C4,
0xCEE6AE2A,0x8AA4C4C6,0xEAAAAAE6,0x864004A2,
0x242A4000,0x2A222A88,0x2AA444E2,0x2AAAA888,
0xA42A8ECA,0xAAA84AAA,0xAA2482A0,0x04044424,
0xE0E04A2E,0xEEEE2EE0,0x08016EC8,0xAEEAE42C,
0x8EEACAC4,0x4AAE4444,0x42000008,0x042A4400,
0x8A28222A,0x2A2444E2,0x0AAAA88A,0xA4AA8A6A,
0x8AA24AAE,0xA4842200,0x040A0240,0x04048E2E,
0xE2EE2EE0,0x42044AC4,0xCE86AE4A,0xEAA487AC,
0x464AA4E6,0x26000000,0x00000800,0x00000000,
0x00008000,0x00000000,0x00000000,0x00000000,
0x0000000F,0x00000004,0x00040004,0x00080004,
0x00000004,0x00000004,0x000C0004,0x00000004,
0x00100004,0x00140004,0x00180004,0x001C0004,
0x00200004,0x00240004,0x00280004,0x002C0004,
0x00300004,0x00340004,0x00380004,0x003C0004,
0x00400004,0x00440004,0x00480004,0x004C0004,
0x00500004,0x00540004,0x00580004,0x005C0004,
0x00600004,0x00640004,0x00680004,0x006C0004,
0x00700004,0x00000004,0x00740004,0x00780004,
0x007C0004,0x00800004,0x00840004,0x00880004,
0x008C0004,0x00900004,0x00940004,0x00980004,
0x009C0004,0x00A00004,0x00A40004,0x00A80004,
0x00AC0004,0x00B00004,0x00B40004,0x00B80004,
0x00BC0004,0x00C00004,0x00C40004,0x00C80004,
0x00CC0004,0x00D00004,0x00D40004,0x00D80004,
0x00DC0004,0x00E00004,0x00E40004,0x00E80004,
0x00EC0004,0x00540004,0x005400C3,0x66E00000,
0x04002C30,0x78303035,0x43303030,0x342C0A09,
0x09307830,0x30363030,0x3030342C,0x30783030,
0x36343030,0x30342C30,0x78303036,0x38303030,
0x342C3078,0x30303643,0x30303034,0x2C0A0909,
0x30783030,0x37303030,0x30342C30,0x78303030,
0x30303030,0x342C3078,0x30303734,0x30303034,
0x2C307830,0x30373830
};
Pixel6Font . tf_Message . mn_Node . ln_Name = "Pixel.font";
Pixel6Font . tf_Message . mn_Node . ln_Type = NT_FONT;
Pixel6Font . tf_Message . mn_Node . ln_Pri = 0;
Pixel6Font . tf_YSize = 6;
Pixel6Font . tf_Style = 0;
Pixel6Font . tf_Flags = 66;
Pixel6Font . tf_XSize = 4;
Pixel6Font . tf_Baseline = 4;
Pixel6Font . tf_BoldSmear = 1;
Pixel6Font . tf_Accessors = 0;
Pixel6Font . tf_LoChar = 32;
Pixel6Font . tf_HiChar = 95;
Pixel6Font . tf_CharData = (APTR)&Pixel6Dump[0];
Pixel6Font . tf_Modulo = 30;
Pixel6Font . tf_CharLoc = (APTR)((char *)&Pixel6Dump[0] + (0xC4EE3A - 0xC4ED86));
Pixel6Font . tf_CharSpace = 0;
Pixel6Font . tf_CharKern = 0;
return(&Pixel6Font);
}
/* CloseAll(ReturnCode) :
*
* Gibt allen angeforderten Speicher frei, schließt
* Libraries, Devices, Fenster, etc. und verläßt das
* Programm.
*/
void
CloseAll(ReturnCode)
long ReturnCode;
{
register short i;
DoPosition = FALSE;
/* Die beiden Sprites brauchen wir nicht mehr. Deshalb
* ab in die Wüste damit.
*/
FreeSprite(2);
FreeSprite(3);
if(Window)
{
while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
ReplyMsg(Massage);
CloseWindow(Window);
}
/* Bitmapdaten freigeben. */
for(i = 0 ; i < 2 ; i++)
if(PointerBMap . Planes[i])
FreeRaster(PointerBMap . Planes[i],16,72);
if(IntuitionBase)
{
/* Intuition wieder Kontrolle über die
* eigenen Routinen geben.
*/
Forbid();
SetFunction(IntuitionBase,-0x42,OldCloseScreen);
Permit();
CloseLibrary(IntuitionBase);
}
if(GfxBase)
CloseLibrary(GfxBase);
CloseTimerDevice();
/* Den MessagePort, mit dem wir erreichbar waren,
* schließen.
*/
if(MouseClockPort)
DeletePort(MouseClockPort);
RemVBlankServer();
exit(ReturnCode);
}
/* OpenAll() :
*
* Öffnet alles, was geöffnet werden muß und
* bereitet Speicher vor, den wir später brauchen
* werden.
*/
void
OpenAll()
{
register short i;
if(!(MouseClockPort = (struct MsgPort *)CreatePort("MouseClockPort",0)))
CloseAll(20);
if(!OpenTimerDevice())
CloseAll(20);
if(!(IntuitionBase = (VOID *)OpenLibrary("intuition.library",LIBRARY_VERSION)))
CloseAll(20);
/* Jetzt hängen wir unsere eigene CloseScreen()
* Routine ins System.
*/
Forbid();
OldCloseScreen = SetFunction(IntuitionBase,-0x42,NuCloseScreen);
Permit();
if(!(GfxBase = (VOID *)OpenLibrary("graphics.library",LIBRARY_VERSION)))
CloseAll(20);
/* Fenster öffnen und richtig plazieren. */
if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
CloseAll(20);
WindowToBack(Window);
/* Kleine Information, falls das Fenster gerade aktiv ist. */
SetWindowTitles(Window,-1,NULL);
/* ED-Symbol einzeichnen. */
DrawImage(Window -> RPort,&ClipImage,4,0);
/* Sprites initialisieren. */
Position1 . height = 72;
Position1 . x = 0;
Position1 . y = 0;
Position2 . height = 72;
Position2 . x = 0;
Position2 . y = 0;
if(GetSprite(&Position1,2) < 0)
CloseAll(20);
if(GetSprite(&Position2,3) < 0)
CloseAll(20);
/* Mini-Zeichenbereich zum Vorbereiten der Sprites
* initialisieren.
*/
InitBitMap(&PointerBMap,2,16,72);
InitRastPort(&PointerRPort);
PointerRPort . BitMap = &PointerBMap;
for(i = 0 ; i < 2 ; i++)
if(!(PointerBMap . Planes[i] = (PLANEPTR)AllocRaster(16,72)))
CloseAll(20);
/* Zeichensatz setzen und Zeichenfarbe einstellen. */
SetFont(&PointerRPort,OpenPixel6Font());
SetAPen(&PointerRPort,1);
SetBPen(&PointerRPort,0);
SetDrMd(&PointerRPort,JAM1);
DoPosition = TRUE;
/* Jetzt wird die Spritekontrolle aktiviert. */
AddVBlankServer();
}
/* WhichDate() :
*
* Trägt das aktuelle Datum in eine Zeichenkette ein,
* die später von uns genutzt werden wird.
*/
char *
WhichDate()
{
static char Buff[10];
struct DateStamp Date;
long n,Month,Day,Year;
/* Tolle Technik nicht wahr? Stammt von ...äh,
* Rob Peck... oder, hmm... Tom Rokicki?
*/
DateStamp(&Date);
n = Date . ds_Days - 2251;
Year = (4 * n + 3) / 1461;
n -= 1461 * Year / 4;
Year += 1984;
Month = (5 * n + 2) / 153;
Day = n - (153 * Month + 2) / 5 + 1;
Month += 3;
if(Month > 12)
{
Year++;
Month -= 12;
}
Year -= 1900;
/* Europäisches Format: Tag. Monat. Jahr */
sprintf(Buff,"%02d-%02d-%02d",Day,Month,Year);
return(Buff);
}
/* WhichTime() :
*
* Trägt die aktuelle Zeit in eine Zeichenkette ein, die
* wir später verwenden werden.
*/
char *
WhichTime()
{
static char Buff[10];
struct DateStamp TimeStamp;
long Hours,Minutes,Seconds;
DateStamp(&TimeStamp);
Hours = TimeStamp . ds_Minute / 60;
Minutes = TimeStamp . ds_Minute % 60;
Seconds = TimeStamp . ds_Tick / TICKS_PER_SECOND;
/* 24 Stunden-Format. */
sprintf(Buff,"%2d:%02d:%02d",Hours,Minutes,Seconds);
return(Buff);
}
/* WhichMem(Type) :
*
* Trägt den freien Speicher eines Typs in eine
* Zeichenkette ein, die auch in die Sprites
* einzeichnet werden wird.
*/
char *
WhichMem(Type)
long Type;
{
static char Buff[10];
long BlockSize;
BlockSize = AvailMem(Type);
sprintf(Buff,"%8d",BlockSize);
return(Buff);
}
/* Diese beiden Zeilen schließen zwei Routinen aus,
* die wir nicht benötigen; es spart zudem ein wenig
* Speicher.
*/
void _cli_parse(){}
void _wb_parse(){}
/* MapToSprite(Sprite,BMap) :
*
* Wandelt den Inhalt einer Bitmap in ein Array
* aus UWORDs um, das dem typischen Format eines
* Hardwaresprites entspricht.
*/
void
MapToSprite(Sprite,BMap)
UWORD Sprite[];
struct BitMap *BMap;
{
register short i,j = 0;
UWORD *Plane[2];
/* Ein Hardwaresprite hat ein recht "drolliges"
* Format, das sich sonst in keiner anderen
* Form auf dem Amiga findet:
*
* 2 UWORDs für Position und Kontrolldaten
* n UWORDs für die eigentlich Spritedaten,
* wobei sich die Daten für beide Planes
* abwechseln.
* 2 UWORDs für dubiose Zwecke.
*
* Die Daten für das Sprite folgen nicht wie auf
* dem Amiga üblich blockweise, sondern Zeile
* für Zeile gemischt.
*/
Plane[0] = (UWORD *)BMap -> Planes[0];
Plane[1] = (UWORD *)BMap -> Planes[1];
/* Spritedaten löschen. */
for(i = 0 ; i < 72 * 2 ; i++)
Sprite[2 + i] = 0;
/* Bitplanes in Sprite-Format wandeln. */
for(i = 0 ; i < 72 ; i++)
for(j = 0 ; j < 2 ; j++)
Sprite[2 + (2 * i) + j] = Plane[j][i];
}
/* DoPtrTxt(Y,Txt) :
*
* Druckt einen Text in die Bitmap, die hinterher
* in ein Sprite umgewandelt wird. Um den Kontrast
* zu steigern, wird noch ein Schatten hinzugefügt.
*/
void
DoPtrTxt(Y,Txt)
LONG Y;
char *Txt;
{
/* Schatten einzeichnen. */
Move(&PointerRPort,1,Y + 1);
SetAPen(&PointerRPort,2);
Text(&PointerRPort,Txt,4);
/* Schrift einzeichnen. */
Move(&PointerRPort,0,Y);
SetAPen(&PointerRPort,1);
Text(&PointerRPort,Txt,4);
}
/* AdjustColours() :
*
* Die Farben der Anzeige von MouseClock sind von den
* Farben des Mauszeigers abhängig. In dieser Funktion
* werden sie aus den Preferences herauskopiert.
*/
void
AdjustColours()
{
struct Preferences *Prefs;
register short i;
/* Puffer anlegen. */
if(Prefs = (struct Preferences *)AllocMem(sizeof(struct Preferences),MEMF_PUBLIC))
{
/* Preferences kopieren. */
GetPrefs(Prefs,sizeof(struct Preferences));
/* Schattenfarbe in Komponenten aufsplitten. */
Shadow[0] = ((Prefs -> color18 >> 8) & 0xF);
Shadow[1] = ((Prefs -> color18 >> 4) & 0xF);
Shadow[2] = ((Prefs -> color18 ) & 0xF);
/* Zeichenfarbe in Komponenten aufsplitten. */
Render[0] = ((Prefs -> color19 >> 8) & 0xF);
Render[1] = ((Prefs -> color19 >> 4) & 0xF);
Render[2] = ((Prefs -> color19 ) & 0xF);
/* Puffer wieder freigeben. */
FreeMem(Prefs,sizeof(struct Preferences));
}
}
/* main() :
*
* Endlich! Nach soviel Vorbereitung nun schließlich
* das Hauptprogramm.
*/
void
main()
{
/* Fall MouseClock ein zweites Mal gestartet
* wird, teilt es dem schon laufenden Task mit, daß
* er sich entfernen soll. Diese Nachricht wird mit
* den folgenden Strukturen verschickt.
*/
struct MsgPort *ReplyPort;
struct Message WakeUp,*Terminate;
struct DMSFragment *DMS = (struct DMSFragment *)FindPort("DMouse");
LONG MouseTimeout = 4;
/* Zeichenpuffer, um die gewünschten Daten auf zwei
* Sprites verteilen zu können.
*/
char DateBuff1[5],DateBuff2[5];
char TimeBuff1[5],TimeBuff2[5];
char FastBuff1[5],FastBuff2[5];
char ChipBuff1[5],ChipBuff2[5];
char *ptr;
/* Letzte Position des Mauszeigers. */
LONG LastX = 0,LastY = 0;
/* Wie oft lief die Prüfschleife schon durch, ohne
* daß sich der Mauszeiger bewegte und wie
* oft lief sie schon durch, ohne daß der Inhalt der
* Sprites verändert werden mußte?
*/
LONG MoveCount = 0,i;
/* Eingabeart, schon wieder so eine Erfindung von =RJ=,
* was meint ihr, welchen Ärger ich mit ProSuite
* hatte! Ich habe fast alles noch einmal schreiben
* müssen, da die Hälfte der Includes zu nichts zu
* gebrauchen war!
*/
ULONG Class;
/* Falls schon eine MouseClock läuft, wird ihr
* eine Nachricht zugesandt, die sie dazu veranlassen
* soll, sich zu entfernen.
*/
if(MouseClockPort = (struct MsgPort *)FindPort("MouseClockPort",0))
{
/* Die Rückantwort soll hier eingehen. */
if(!(ReplyPort = (struct MsgPort *)CreatePort(NULL,0)))
exit(20);
/* Nachricht initialisieren. */
WakeUp . mn_Node . ln_Type = NT_MESSAGE;
WakeUp . mn_Length = sizeof(struct Message);
WakeUp . mn_ReplyPort = ReplyPort;
/* An den MessagePort schicken und
* auf Bestätigung warten.
*/
PutMsg(MouseClockPort,&WakeUp);
Wait(1 << ReplyPort -> mp_SigBit);
/* Rückantwortsport löschen. */
DeletePort(ReplyPort);
exit(0);
}
/* Alles öffnen und Farben der Sprites anpassen. */
OpenAll();
AdjustColours();
FOREVER
{
/* Sollen wir uns schon entfernen? */
if(Terminate = (struct Message *)GetMsg(MouseClockPort))
{
ReplyMsg(Terminate);
CloseAll(0);
}
if(DMS)
if((MouseTimeout = DMS -> MTo - 1) < 0)
MouseTimeout = 0;
Class = NULL;
/* Ist irgendetwas am Fenster passiert? */
if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
{
Class = Massage -> Class;
ReplyMsg(Massage);
}
/* Schließgadget gewählt? */
if(Class == CLOSEWINDOW)
CloseAll(0);
/* Die Farben des Mauszeigers könnten sich
* geändert haben.
*/
if(Class == NEWPREFS)
AdjustColours();
/* Das ED-Symbol muß nachgezeichnet werden. */
if(Class == REFRESHWINDOW)
{
BeginRefresh(Window);
DrawImage(Window -> RPort,&ClipImage,4,0);
EndRefresh(Window,TRUE);
}
/* Wir wurden aktiviert und melden uns
* auch gleich.
*/
if(Class == ACTIVEWINDOW)
{
PrintIText(Window -> WScreen -> BarLayer -> rp,&AboutTxt[0],4,0);
DrawImage(Window -> WScreen -> BarLayer -> rp,&ClipImage,210,0);
}
/* Wenn sich der Mauszeiger seit fünf
* Sekunden nicht bewegt hat, wird die
* Anzeige von MouseClock ausgeschaltet.
* Bewegt sich der Mauszeiger anschließend
* jedoch wieder, werden die Sprites
* angeschaltet.
*/
if(CurX != LastX || CurY != LastY)
{
/* Sprites wieder anschalten. */
if(MoveCount > MouseTimeout)
{
GetSprite(&Position1,2);
GetSprite(&Position2,3);
DoPosition = TRUE;
}
MoveCount = 0;
}
else
{
if((++MoveCount) >= MouseTimeout)
{
/* Sprites ausschalten. */
if(MoveCount == MouseTimeout)
{
DoPosition = FALSE;
WaitTOF();
WaitTOF();
FreeSprite(2);
FreeSprite(3);
}
continue;
}
}
/* Nur um sicherzugehen, daß wir es überhaupt
* bemerken, wenn sich der Mauszeiger nicht
* bewegt hat.
*/
LastX = CurX;
LastY = CurY;
/* Datum abfragen und aufspalten. */
ptr = WhichDate();
for(i = 0 ; i < 4 ; i++)
{
DateBuff1[i] = ptr[i];
DateBuff2[i] = ptr[i + 4];
}
DateBuff1[4] = DateBuff2[4] = 0;
/* Zeit abfragen und aufspalten. */
ptr = WhichTime();
for(i = 0 ; i < 4 ; i++)
{
TimeBuff1[i] = ptr[i];
TimeBuff2[i] = ptr[i + 4];
}
TimeBuff1[4] = TimeBuff2[4] = 0;
/* Chip-Ram abfragen und aufspalten. */
ptr = WhichMem(MEMF_CHIP);
for(i = 0 ; i < 4 ; i++)
{
ChipBuff1[i] = ptr[i];
ChipBuff2[i] = ptr[i + 4];
}
ChipBuff1[4] = ChipBuff2[4] = 0;
/* Fast-Ram abfragen und aufspalten. */
ptr = WhichMem(MEMF_FAST);
for(i = 0 ; i < 4 ; i++)
{
FastBuff1[i] = ptr[i];
FastBuff2[i] = ptr[i + 4];
}
FastBuff1[4] = FastBuff2[4] = 0;
/* Bitmap löschen und linkes
* Sprite erzeugen.
*/
SetRast(&PointerRPort,0);
DoPtrTxt(10,TimeBuff2);
DoPtrTxt(22,DateBuff2);
DoPtrTxt(34,ChipBuff2);
DoPtrTxt(46,FastBuff2);
MapToSprite(Pointer2Data,&PointerBMap);
/* Bitmap löschen und rechtes
* Sprite erzeugen.
*/
SetRast(&PointerRPort,0);
DoPtrTxt(4,"TIME");
DoPtrTxt(10,TimeBuff1);
DoPtrTxt(16,"DATE");
DoPtrTxt(22,DateBuff1);
DoPtrTxt(28,"CHIP");
DoPtrTxt(34,ChipBuff1);
DoPtrTxt(40,"FAST");
DoPtrTxt(46,FastBuff1);
MapToSprite(Pointer1Data,&PointerBMap);
/* Neue Sprites anzeigen. */
ChangeSprite(NULL,&Position1,Pointer1Data);
ChangeSprite(NULL,&Position2,Pointer2Data);
/* Eine Zeitperiode warten. */
WaitTime(1,0);
}
}